package com.colin.library.view.custom;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;

import com.colin.library.view.help.MetricsHelp;
import com.colin.library.view.help.ViewLogHelp;

/**
 * Created by shihang0001 on 2016/6/8.
 */
public class CustomViewCanvas extends View {
    private Paint mPaint;
    private String string = "Hello World!";
    private int textsize = 50;
    private Context context;
    private DisplayMetrics dm;
    private int mScreenWidth, mScreenHeight;
    private int viewWidth, viewHeight;
    private VelocityTracker mVelocityTracker = null;
    private GestureDetector gestureDetector = null;
    private final static int LINE_STYLE_DOTTED = 0;//虚线
    private final static int LINE_STYLE_SOLID = 1;//实线
    private final static int LINE_STYLE_SMOOTH_OF_SOLID = 2;//平滑的实线

    public void setString(String string) {
        this.string = string;
        invalidateView();
    }

    public String getString() {
        return string;
    }

    public void setTextsize(int textsize) {
        this.textsize = MetricsHelp.px2sp(context, textsize);
    }

    public CustomViewCanvas(Context context) {
        this(context, null);
    }

    public CustomViewCanvas(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomViewCanvas(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }

    /**
     * 初始化画笔
     */
    private void init() {
        //    自定义View：常用工具类
        //    Configuration
        //    ViewConfiguration
        //    GestureDetector
        //    VelocityTracker
        //    Scroller
        //    ViewDragHelper
        showConfiguration();
        showViewConfiguration();
        showGestureDetector();
        showVelocityTracker();
        //Scroller
        showDragHelper();//适用于ViewGroup
        dm = getResources().getDisplayMetrics();
        mScreenWidth = dm.widthPixels;
        mScreenHeight = dm.heightPixels;
        // 实例化一个画笔工具
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        // 设置字体大小
        mPaint.setTextSize(MetricsHelp.px2sp(context, textsize));
        // 设置画笔颜色
        mPaint.setColor(Color.RED);
        mPaint.reset();

    }

    /**
     * Configuration:
     * This class describes all device configuration information that can
     * impact the resources the application retrieves.
     * Configuration用来描述设备的配置信息。
     * 比如用户的配置信息：locale和scaling等等
     * 比如设备的相关信息：输入模式，屏幕大小， 屏幕方向等等
     * 我们经常采用如下方式来获取需要的相关信息:
     */
    private void showConfiguration() {
        Configuration configuration = getResources().getConfiguration();
        //获取国家码
        int countryCode = configuration.mcc;
        ViewLogHelp.d("获取国家码:" + countryCode);
        //获取网络码
        int networkCode = configuration.mnc;
        ViewLogHelp.d("获取网络码:" + networkCode);
        //判断横竖屏
        if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
            ViewLogHelp.d("判断横竖屏:竖屏");
        } else {
            ViewLogHelp.d("判断横竖屏:横屏");
        }
    }

    /**
     * ViewConfiguration:
     * Contains methods to standard constants used in the UI for timeouts,
     * sizes, and distances.
     * ViewConfiguration提供了一些自定义控件用到的标准常量，比如尺寸大小，滑动距离，敏感度等等。
     * 可以利用ViewConfiguration的静态方法获取一个实例
     * ViewConfiguration viewConfiguration=ViewConfiguration.get(context);
     * 在此介绍ViewConfiguration的几个对象方法。
     */
    private void showViewConfiguration() {
        ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
        //获取touchSlop。该值表示系统所能识别出的被认为是滑动的最小距离
        int touchSlop = viewConfiguration.getScaledTouchSlop();
        ViewLogHelp.d("获取touchSlop:" + touchSlop + "\n");
        //获取Fling速度的最小值和最大值
        int minimumVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
        int maximumVelocity = viewConfiguration.getScaledMaximumFlingVelocity();
        ViewLogHelp.d("Fling速度的最小值:" + minimumVelocity);
        ViewLogHelp.d("Fling速度的最大值:" + maximumVelocity);
        //判断是否有物理按键
        boolean isHavePermanentMenuKey = viewConfiguration.hasPermanentMenuKey();
        ViewLogHelp.d("判断是否有物理按键:" + String.valueOf(isHavePermanentMenuKey));
//        ViewConfiguration还提供了一些非常有用的静态方法，比如：
        //双击间隔时间.在该时间内是双击，否则是单击
        int doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
        ViewLogHelp.d("双击间隔时间.在该时间内是双击，否则是单击:" + doubleTapTimeout);
        //按住状态转变为长按状态需要的时间
        int longPressTimeout = ViewConfiguration.getLongPressTimeout();
        ViewLogHelp.d("按住状态转变为长按状态需要的时间:" + longPressTimeout);
        //重复按键的时间
        int keyRepeatTimeout = ViewConfiguration.getKeyRepeatTimeout();
        ViewLogHelp.d("重复按键的时间:" + keyRepeatTimeout);
    }

    /**
     * GestureDetector :
     * 可以在onTouchEvent()中自己处理手势。其实Android系统也给我们提供了一个手势处理的工具，这就是GestureDetector手势监听类。
     * 利用GestureDetector可以简化许多操作，轻松实现一些常用的功能
     */
    private void showGestureDetector() {
        gestureDetector = new GestureDetector(context, new GestureListenerImpl());
    }

    /**
     * VelocityTracker :
     * 速度追踪,VelocityTracker用于跟踪触摸屏事件（比如，Flinging及其他Gestures手势事件等）的速率。
     * 第一步：开始速度追踪
     * 第二步：Touch事件添加
     * 第三步：获取追踪到的速度
     * 第四步：解除速度追踪
     */
    private void showVelocityTracker() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
    }

    private int getScrollVelocity() {
        // 设置VelocityTracker单位.1000表示1秒时间内运动的像素
        mVelocityTracker.computeCurrentVelocity(1000);
        // 获取在1秒内X方向所滑动像素值
        int xVelocity = (int) mVelocityTracker.getXVelocity();
        ViewLogHelp.d(xVelocity);
        return Math.abs(xVelocity);
    }

    /**
     * 对外公开方法 ，实现关闭
     */
    public void stopVelocityTracker() {
        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    /**
     * 第一点：scrollTo()和scrollBy()的关系:
     * 这就是说scrollBy( )调用了scrollTo( )，最终起作用的是scrollTo( )方法。
     * 第二点：scroll的本质:
     * scrollTo( )和scrollBy( )移动的只是View的内容，而且View的背景是不移动
     * 第三点：scrollTo( )和scrollBy( )方法的坐标说明
     * 比如我们对于一个TextView调用scrollTo(0,25) ；那么该TextView中的content(比如显示的文字:Hello)会怎么移动呢?
     * 向下移动25个单位？不！恰好相反！！这是为什么呢?
     * 因为调用该方法会导致视图重绘，即会调用
     * public void invalidate(int l, int t, int r, int b)
     * 此处的l,t,r,b四个参数就表示View原来的坐标.
     * 在该方法中最终会调用:
     * tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY);
     * p.invalidateChild(this, tmpr);
     * 其中tmpr是一个Rect，this是原来的View；通过这两行代码就把View在一个Rect中重绘。
     * 请注意第一行代码:
     * 原来的l和r均减去了scrollX
     * 原来的t和b均减去了scrollY
     * 就是说scrollX如果是正值,那么重绘后的View的宽度反而减少了;反之同理
     * 就是说scrollY如果是正值,那么重绘后的View的高度反而减少了;反之同理
     * 所以，TextView调用scrollTo(0,25)和我们的理解相反
     * scrollBy(int x,int y)方法与上类似,不再多说了.
     */
    @Override
    public void scrollBy(int x, int y) {
        super.scrollBy(x, y);
//        scrollTo(mScrollX + x, mScrollY + y);
    }

    /**
     * ViewDragHelper:
     * 需要用户手指拖动其内部的某个View，此时就需要在onInterceptTouchEvent()和onTouchEvent()这两个方法中写不少逻辑了，
     * 比如处理：拖拽移动，越界，多手指的按下，加速度检测等等
     * ViewDragHelper可以极大的帮我们简化类似的处理，它提供了一系列用于处理用户拖拽子View的辅助方法和与其相关的状态记录。比较常见的：QQ侧滑菜单，Navigation Drawer的边缘滑动，都可以由它实现。
     * ViewDragHelper的使用并不复杂，在此通过一个示例展示其常用的用法
     */
    private void showDragHelper() {

    }

    private class GestureListenerImpl implements OnGestureListener {
        //触摸屏幕时均会调用该方法
        @Override
        public boolean onDown(MotionEvent e) {
            ViewLogHelp.d("---> 手势中的onDown方法");
            return false;
        }

        //手指在屏幕上拖动时会调用该方法
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            ViewLogHelp.d("---> 手势中的onFling方法");
            return false;
        }

        //手指长按屏幕时均会调用该方法
        @Override
        public void onLongPress(MotionEvent e) {
            ViewLogHelp.d("---> 手势中的onLongPress方法");
        }

        //手指在屏幕上滚动时会调用该方法
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            ViewLogHelp.d("---> 手势中的onScroll方法");
            return false;
        }

        //手指在屏幕上按下,且未移动和松开时调用该方法
        @Override
        public void onShowPress(MotionEvent e) {
            ViewLogHelp.d("---> 手势中的onShowPress方法");
        }

        //轻击屏幕时调用该方法
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            ViewLogHelp.d("---> 手势中的onSingleTapUp方法");
            return false;
        }
    }
//    这样一个大大的"Hello World!"呈现在我们面前，可能有的人会问到底怎样去自定义一个控件呢？别急我们慢慢的，一点一点的去学习，首先你可以想象一下，假如我要求你去画一个空心的圆，你会怎么做，首先你要拿张白纸，然后你会问我圆的半径多大？圆的位置在哪？圆的线条颜色是什么？圆的线条粗细是多少？等我把这些问题都告诉你之后，你就会明白要求，并按照这个要求去画一个圆。我们自定义控件呢，也是这样需要下面三个步骤：
//    ①重写onMeasure(获得半径的大小)
//    ②重写onLayout(获得圆的位置)
//    ③重写onDraw(用实例化的画笔包括:颜色，粗细等去绘画)

    /**
     * View的这个方法是被它的父控件调用的，也就是说widthMeasureSpec和heightMeasureSpec是通过父控件传递进来的
     * 默认只有EXACTLY 属性  需要支持wrap_content属性必须重写此方法
     * MeasureSpec 非常重要这个类:1、获取View的测量模式 2、View想绘制多大
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

        //处理 wrap_content问题
        int defaultDimension = MetricsHelp.dp2px(context, 100);

        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(defaultDimension, defaultDimension);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(defaultDimension, heightSpecSize);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSpecSize, defaultDimension);
        }

        //自定义
//        measureWidth(widthMeasureSpec);
//        measureHeight(heightMeasureSpec);

    }


    /**
     * 计算宽度
     *
     * @param widthMeasureSpec
     * @return
     */
    private int measureWidth(int widthMeasureSpec) {
        int result = 200;//默认值
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);

        if (specMode == MeasureSpec.EXACTLY) {//大小精确
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {//wrap_content属性
            result = Math.min(result, specSize);
        } else if (specMode == MeasureSpec.UNSPECIFIED) {
            //默认就可以
        }
        return result;
    }

    /**
     * 计算高度
     *
     * @param heightMeasureSpec
     * @return
     */
    private int measureHeight(int heightMeasureSpec) {
        int result = 200;//默认值
        int specMode = MeasureSpec.getMode(heightMeasureSpec);
        int specSize = MeasureSpec.getSize(heightMeasureSpec);

        if (specMode == MeasureSpec.EXACTLY) {//大小精确
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {//wrap_content属性
            result = Math.min(result, specSize);
        } else if (specMode == MeasureSpec.UNSPECIFIED) {
            //默认就可以
        }
        return result;
    }

    /**
     * 在测量完View并使用setMeasuredDimension函数之后View的大小基本上已经确定了，那么为什么还要再次确定View的大小呢？
     * 这是因为View的大小不仅由View本身控制，而且受父控件的影响，所以我们在确定View大小的时候最好使用系统提供的onSizeChanged回调函数。
     *
     * @param w    View宽度
     * @param h    View高度
     * @param oldw 上一次宽度
     * @param oldh 上一次高度
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.viewWidth = w;
        this.viewHeight = h;
    }

    /**
     * 重写onDraw方法
     * Canvas:
     * void drawRect(RectF rect, Paint paint) //绘制区域，参数一为RectF一个区域
     * void drawPath(Path path, Paint paint) //绘制一个路径，参数一为Path路径对象
     * void  drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)  //贴图，参数一就是我们常规的Bitmap对象，参数二是源区域(这里是bitmap)，参数三是目标区域(应该在 canvas的位置和大小)，参数四是Paint画刷对象，因为用到了缩放和拉伸的可能，当原始Rect不等于目标Rect时性能将会有大幅损失。
     * void  drawLine(float startX, float startY, float stopX, float stopY, Paint paint)  //画线，参数一起始点的x轴位置，参数二起始点的y轴位置，参数三终点的x轴水平位置，参数四y轴垂直位置，最后一个参数为Paint画刷对象。
     * void  drawPoint(float x, float y, Paint paint) //画点，参数一水平x轴，参数二垂直y轴，第三个参数为Paint对象。
     * void drawText(String text, float x, float y, Paint paint)  //渲染文本，Canvas类除了上面的还可以描绘文字，参数一是String类型的文本，参数二x轴，参数三y轴，参数四是Paint对象。
     * void  drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) //在路径上绘制文本，相对于上面第二个参数是Path路径对象
     * Paint:
     * void  setARGB(int a, int r, int g, int b)  设置Paint对象颜色，参数一为alpha透明通道
     * void  setAlpha(int a)  设置alpha不透明度，范围为0~255
     * void  setAntiAlias(boolean aa)  //是否抗锯齿
     * void  setColor(int color)  //设置颜色，这里Android内部定义的有Color类包含了一些常见颜色定义
     * void  setFakeBoldText(boolean fakeBoldText)  //设置伪粗体文本
     * void  setLinearText(boolean linearText)  //设置线性文本
     * PathEffect  setPathEffect(PathEffect effect)  //设置路径效果
     * Rasterizer  setRasterizer(Rasterizer rasterizer) //设置光栅化
     * Shader  setShader(Shader shader)  //设置阴影
     * void  setTextAlign(Paint.Align align)  //设置文本对齐
     * void  setTextScaleX(float scaleX)  //设置文本缩放倍数，1.0f为原始
     * void  setTextSize(float textSize)  //设置字体大小
     * Typeface  setTypeface(Typeface typeface)  //设置字体，Typeface包含了字体的类型，粗细，还有倾斜、颜色等。
     * void  setUnderlineText(boolean underlineText)  //设置下划线
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        drawWhiteRect(canvas);
        drawRedLine(canvas);
        drawStrokeRect(canvas);
        drawStrokeCircle(canvas);
        drawOval(canvas);
        drawText(canvas);
        drawTranslate(canvas);
        drawRotate(canvas);
        drawClipRect(canvas);
        drawLine(canvas);

    }
    /**
     * 绘制白色矩形
     *
     * @param canvas
     */
    private void drawWhiteRect(Canvas canvas) {
        mPaint.setColor(Color.RED);
        canvas.drawRect(10, 30, mScreenWidth / 2 - 10, 100, mPaint);
        mPaint.reset();
    }


    /**
     * 绘制带边框的矩形
     *
     * @param canvas
     */
    private void drawStrokeRect(Canvas canvas) {
        mPaint.setStrokeWidth(10);
        mPaint.setARGB(150, 90, 255, 0);
        mPaint.setStyle(Paint.Style.STROKE);
        RectF rectF1 = new RectF(mScreenWidth / 2 + 10, 30, mScreenWidth - 10, 100);
        canvas.drawRect(rectF1, mPaint);
        mPaint.reset();
    }


    /**
     * 绘制椭圆
     * float left, float top, float right, float bottom
     *
     * @param canvas
     */
    private void drawOval(Canvas canvas) {
        mPaint.setColor(Color.YELLOW);
        RectF rectF2 = new RectF(10, 110, mScreenWidth / 2 - 10, 200);
        canvas.drawOval(rectF2, mPaint);
        mPaint.reset();
    }

    /**
     * 绘制实心圆
     *
     * @param canvas
     */
    private void drawStrokeCircle(Canvas canvas) {
        mPaint.setStrokeWidth(14);
        mPaint.setColor(Color.GREEN);
        mPaint.setAntiAlias(true);
        canvas.drawCircle(mScreenWidth / 4 * 3, 155, 45, mPaint);
        mPaint.reset();
    }


    /**
     * 绘制直线
     *
     * @param canvas
     */
    private void drawRedLine(Canvas canvas) {
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(5);
        canvas.drawLine(10, 210, mScreenWidth - 10, 210, mPaint);
        mPaint.reset();
    }

    /**
     * 绘制文字
     *
     * @param canvas
     */
    private void drawText(Canvas canvas) {
        mPaint.setColor(Color.BLACK);
        mPaint.setTextSize(textsize);
        mPaint.setUnderlineText(true);
        canvas.drawText(string, mScreenWidth / 2, 230, mPaint);
        mPaint.reset();
    }

    /**
     * 平移 移动坐标轴  x y轴的  x + translate_dx(5)  y+translate_dy(10)
     *
     * @param canvas
     */
    private void drawTranslate(Canvas canvas) {
        canvas.save();//保存之前的画板；新建一个透明的画板
        Rect rect = new Rect(0, 260, mScreenWidth, mScreenHeight);
        canvas.clipRect(rect);
        canvas.drawColor(Color.GREEN);
        mPaint.setTextSize(textsize);
        mPaint.setColor(Color.BLUE);
        canvas.drawText("蓝色字体为Translate前所画", 10, 280, mPaint);
        canvas.translate(5, 20);
        mPaint.setColor(Color.BLACK);
        canvas.drawText("黑色字体为Translate后所画", 10, 280, mPaint);
        mPaint.reset();
        canvas.restore();//透明的画板，放到之前的画板中
    }

    /**
     * rotate实现旋转 坐标轴转动，0，0原点转动
     *
     * @param canvas
     */
    private void drawRotate(Canvas canvas) {
        canvas.save();//保存之前的画板；新建一个透明的画板
        Rect rect = new Rect(0, 330, mScreenWidth, mScreenHeight);
        canvas.clipRect(rect);
        canvas.drawColor(Color.RED);
        mPaint.setTextSize(textsize);
        mPaint.setColor(Color.BLUE);
        canvas.drawText("绿色字体为Rotate前所绘", 0, 350, mPaint);
        canvas.rotate(30);
        mPaint.setColor(Color.BLACK);
        canvas.drawText("黑色字体为Rotate后所绘", 175, 300, mPaint);//计算而得来的
        mPaint.reset();
        canvas.restore();//透明的画板，放到之前的画板中
    }

    /**
     * 剪裁前的区域 升级
     * canvas.save和canvas.restore
     * 刚才在说canvas.clipRect( )时，有人可能有这样的疑问：在调用canvas.clipRect( )后，如果还需要在剪裁范围外绘图该怎么办？
     * 是不是系统有一个canvas.restoreClipRect( )方法呢？去看看官方的API就有点小失望了，我们期待的东西是不存在的；
     * 不过可以换种方式来实现这个需求，这就是即将要介绍的canvas.save和canvas.restore。
     * 看到这个玩意，可能绝大部分人就想起来了Activity中的onSaveInstanceState和onRestoreInstanceState这两者用来保存和还原Activity的某些状态和数据。
     * canvas也可以这样么？
     * canvas.save先来看这个玩意，它表示画布的锁定。如果我们把一个妹子锁在屋子里，那么外界的刮风下雨就影响不到她了；
     * 同理，如果对一个canvas执行了save操作就表示将已经所绘的图形锁定，之后的绘图就不会影响到原来画好的图形。
     * 既然不会影响到原本已经画好的图形，那之后的操作又发生在哪里呢？
     * 当执行canvas.save( )时会生成一个新的图层(Layer)，并且这个图层是透明的。
     * 此时，所有draw的方法都是在这个图层上进行，所以不会对之前画好的图形造成任何影响。
     * 在进行一些绘制操作后再使用canvas.restore()将这个新的图层与底下原本的画好的图像相结合形成一个新的图像。
     * 打个比方：原本在画板上画了一个姑娘，我又找了一张和画板一样大小的透明的纸(Layer)，
     * 然后在上面画了一朵花，最后我把这个纸盖在了画板上，呈现给世人的效果就是：一个美丽的姑娘手拿一朵鲜花。
     * <p/>
     * <p/>
     * save( )和restore( )最好配对使用，若restore( )的调用次数比save( )多可能会造成异常
     *
     * @param canvas
     */
    private void drawClipRect(Canvas canvas) {
        mPaint.setTextSize(MetricsHelp.px2sp(context, 20));
        mPaint.setColor(Color.GREEN);
        canvas.drawText("绿色部分为Canvas剪裁前的区域", 10, 440, mPaint);
        canvas.save();//保存之前的画板  ；新建一个透明的画板
        Rect rect = new Rect(20, 450, mScreenWidth - 20, mScreenHeight);
        canvas.clipRect(rect);
        canvas.drawColor(Color.YELLOW);
        mPaint.setColor(Color.BLACK);
        canvas.drawText("黄色部分为Canvas剪裁后的区域", 30, 470, mPaint);
        canvas.restore();//透明的画板，放到之前的画板中
        mPaint.setColor(Color.BLUE);
        canvas.drawText("蓝色部分为Canvas.restore后的区域", 10, 490, mPaint);
        mPaint.reset();
    }


    /**
     * PathEffect
     * 我们可以通过canvas.drawPath( )绘制一些简单的路径。但是假若需要给路径设置一些效果或者样式，
     * 这时候就要用到PathEffect了。
     * PathEffect有如下几个子类：
     * CornerPathEffect
     * 用平滑的方式衔接Path的各部分
     * DashPathEffect
     * 将Path的线段虚线化
     * PathDashPathEffect
     * 与DashPathEffect效果类似但需要自定义路径虚线的样式
     * DiscretePathEffect
     * 离散路径效果
     * ComposePathEffect
     * 两种样式的组合。先使用第一种效果然后在此基础上应用第二种效果
     * SumPathEffect
     * 两种样式的叠加。先将两种路径效果叠加起来再作用于Path
     * 以CornerPathEffect和DashPathEffect为示例：
     *
     * @param canvas
     */
    private void drawLine(Canvas canvas) {
        canvas.save();//保存之前的画板  ；新建一个透明的画板
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.BLUE);
        mPaint.setStrokeWidth(8);
        Path path = new Path();
        path.moveTo(15, 60);
        for (int i = 0; i <= 35; i++) {
            path.lineTo(i * 30, (float) (Math.random() * 150));
        }
        canvas.translate(0, 500);
        canvas.drawPath(path, mPaint);
        canvas.translate(0, 80);
        mPaint.setPathEffect(new CornerPathEffect(60));
        canvas.drawPath(path, mPaint);
        canvas.translate(0, 80);
        mPaint.setPathEffect(new DashPathEffect(new float[]{15, 8}, 1));
        canvas.drawPath(path, mPaint);
        mPaint.reset();
        canvas.restore();//透明的画板，放到之前的画板中
    }

    /**
     * 界面数据就变化:界面刷新
     */
    private void invalidateView() {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            invalidate();
        } else {
            postInvalidate();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mVelocityTracker != null) {
            mVelocityTracker.addMovement(event);
        }
        if (gestureDetector != null) {
            gestureDetector.onTouchEvent(event);
        }
        return super.onTouchEvent(event);
    }


}
